#include "drmDisplay.h"

static uint32_t GetPropertyId(int fd, drmModeObjectProperties *pProps, const char *pName)
{
	drmModePropertyPtr pProperty;
	uint32_t i, id = 0;

	for (i = 0; i < pProps->count_props; i++) {
		pProperty = drmModeGetProperty(fd, pProps->props[i]);
		if (!strcmp(pProperty->name, pName))
			id = pProperty->prop_id;
		drmModeFreeProperty(pProperty);

		if (id)
			break;
	}

	return id;
}

C_DRMDisplay::C_DRMDisplay()
{
}

C_DRMDisplay::~C_DRMDisplay()
{

	drmModeFreeConnector(pModeConn);
	drmModeFreePlaneResources(pModePlaneRes);
	drmModeFreeResources(pModeRes);
	if (pAtomicReq)
		drmModeAtomicFree(pAtomicReq);

	for (T_DRMFramebuffer element : vtDRMFramebuffers) {
		drmModeRmFB(iDevfd, element.FramebufferId);
	}

	close(iDevfd);
}

void C_DRMDisplay::SetFilePath(const char *FilePath)
{
	pDevPath = FilePath;
}

int C_DRMDisplay::InitDRMParam()
{
	drmModeObjectProperties *pProps; // 请求结构体

	iDevfd = open(pDevPath, O_RDWR | O_CLOEXEC);
	if (iDevfd < 0) {
		std::cerr << "Faild to open DRM device" << std::endl;
	}

	pModeRes = drmModeGetResources(iDevfd);

	iConnId = pModeRes->connectors[2];
	pModeConn = drmModeGetConnector(iDevfd, iConnId);

	iCrtcId = pModeRes->crtcs[3];
	// 允许进行图层操作
	drmSetClientCap(iDevfd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
	pModePlaneRes = drmModeGetPlaneResources(iDevfd);
	if (!pModePlaneRes) {
		fprintf(stderr, "drmModeGetPlaneResources failed: %s\n",
				strerror(errno));
		return -ENOENT;
	}
	iPlaneId = pModePlaneRes->planes[0];

	// 运行进行原子操作
	drmSetClientCap(iDevfd, DRM_CLIENT_CAP_ATOMIC, 1);

	pProps = drmModeObjectGetProperties(iDevfd, iConnId, DRM_MODE_OBJECT_CONNECTOR);
	iPropertyCrtcId = GetPropertyId(iDevfd, pProps, "CRTC_ID");
	drmModeFreeObjectProperties(pProps);

	pProps = drmModeObjectGetProperties(iDevfd, iCrtcId, DRM_MODE_OBJECT_CRTC);
	iPropertyActive = GetPropertyId(iDevfd, pProps, "ACTIVE");
	iPropertyModeId = GetPropertyId(iDevfd, pProps, "MODE_ID");
	drmModeFreeObjectProperties(pProps);

	drmModeCreatePropertyBlob(iDevfd, &pModeConn->modes[0], sizeof(pModeConn->modes[0]), &iBlobId);

	pAtomicReq = drmModeAtomicAlloc();
	if (!pAtomicReq) {
		perror("Failed to allocate atomic request");
		return -1;
	}

	drmModeAtomicAddProperty(pAtomicReq, iCrtcId, iPropertyActive, 1);
	drmModeAtomicAddProperty(pAtomicReq, iCrtcId, iPropertyModeId, iBlobId);
	drmModeAtomicAddProperty(pAtomicReq, iConnId, iPropertyCrtcId, iCrtcId);
	drmModeAtomicCommit(iDevfd, pAtomicReq, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL);

	std::cout << "drmModeAtomicCommit SetCrtc" << std::endl;

	/* get plane properties */
	pProps = drmModeObjectGetProperties(iDevfd, iPlaneId, DRM_MODE_OBJECT_PLANE);
	iPropertyCrtcId = GetPropertyId(iDevfd, pProps, "CRTC_ID");
	iPropertyfbId = GetPropertyId(iDevfd, pProps, "FB_ID");
	iPropertyCrtcX = GetPropertyId(iDevfd, pProps, "CRTC_X");
	iPropertyCrtcY = GetPropertyId(iDevfd, pProps, "CRTC_Y");
	iPropertyCrtcW = GetPropertyId(iDevfd, pProps, "CRTC_W");
	iPropertyCrtcH = GetPropertyId(iDevfd, pProps, "CRTC_H");
	iPropertySrcX = GetPropertyId(iDevfd, pProps, "SRC_X");
	iPropertySrcY = GetPropertyId(iDevfd, pProps, "SRC_Y");
	iPropertySrcW = GetPropertyId(iDevfd, pProps, "SRC_W");
	iPropertySrcH = GetPropertyId(iDevfd, pProps, "SRC_H");
	drmModeFreeObjectProperties(pProps);

	return 0;
}

int C_DRMDisplay::CheckFramebuffExist(int iDrmPrimefd)
{
	if (vtDRMFramebuffers.size() == 0)
		return 0;
	for (T_DRMFramebuffer element : vtDRMFramebuffers) {
		if (element.DrmPrimefd == iDrmPrimefd)
			return 1;
	}
	return 0;
}

int C_DRMDisplay::InitDRMFb(AVFrame *frame, uint32_t format)
{
	int ret;
	AVDRMFrameDescriptor *desc = (AVDRMFrameDescriptor *)frame->data[0];
	uint32_t handles[4] = {0};
	uint32_t pitches[4] = {0};
	uint32_t offsets[4] = {0};

	// check_frame_alignment(frame);

	if (!desc || desc->nb_objects < 1) {
		fprintf(stderr, "Invalid DRM PRIME frame descriptor\n");
		return -1;
	}

	// printf("desc->nb_objects = %d\r\n", desc->nb_objects);
	// printf("desc->nb_layers = %d\r\n", desc->nb_layers);

	// 获取drm帧的格式信息
	// for (int i = 0; i < desc->nb_layers; i++) {
	// 	printf("Layer %d: Format: 0x%x\n", i, desc->layers[i].format);

	// 	// 验证 DRM 格式
	// 	uint32_t format = desc->layers[i].format;
	// 	printf("DRM Format: %s\n", drmGetFormatName(format));
	// }

	// 获取 GEM handles
	// for (int i = 0; i < desc->nb_objects; i++) {
	// 	ret = drmPrimeFDToHandle(d_obj.fd, desc->objects[i].fd, &handles[i]);
	// 	if (ret) {
	// 		perror("drmPrimeFDToHandle failed");
	// 		return -1;
	// 	}
	// }

	drmPrimeFDToHandle(iDevfd, desc->objects[0].fd, &handles[0]);
	drmPrimeFDToHandle(iDevfd, desc->objects[0].fd, &handles[1]);

	// 设置 framebuffer 参数
	pitches[0] = desc->layers[0].planes[0].pitch;  // Y 平面步幅
	offsets[0] = desc->layers[0].planes[0].offset; // Y 平面偏移量
	pitches[1] = desc->layers[0].planes[1].pitch;  // UV 平面步幅
	offsets[1] = desc->layers[0].planes[1].offset; // UV 平面偏移量

	std::cout << "pitches[0] = " << pitches[0] << std::endl;
	std::cout << "offsets[0] = " << offsets[0] << std::endl;
	std::cout << "pitches[1] = " << pitches[1] << std::endl;
	std::cout << "offsets[1] = " << offsets[1] << std::endl;

	// 列出plane支持的格式
	// drmModePlane *plane = drmModeGetPlane(d_obj.fd, d_obj.plane_id);
	// if (plane) {
	//     printf("Plane supports %d formats:\n", plane->count_formats);
	//     for (uint32_t i = 0; i < plane->count_formats; i++) {
	//         printf("Format: 0x%x\n", plane->formats[i]);
	//         printf("DRM Format: %s\n", drmGetFormatName(plane->formats[i]));
	//     }
	//     drmModeFreePlane(plane);
	// } else {
	//     perror("Failed to get plane");
	// }

	// 添加 framebuffer
	uint32_t iFramebufferId;
	ret = drmModeAddFB2(iDevfd, frame->width, frame->height, format,
						handles, pitches, offsets, &iFramebufferId, 0);
	if (ret) {
		printf("drmModeAddFB2 ret = %d\r\n", ret);
		perror("drmModeAddFB2 failed");
		return -1;
	}

	DRMFramebuffer tDRMFrameBuff;
	tDRMFrameBuff.DrmPrimefd = desc->objects[0].fd;
	tDRMFrameBuff.FramebufferId = iFramebufferId;
	vtDRMFramebuffers.push_back(tDRMFrameBuff);

	printf("init_drm DrmPrimefd = %d, FramebufferId = %d\r\n", tDRMFrameBuff.DrmPrimefd, tDRMFrameBuff.FramebufferId);
	return 0;
}

int C_DRMDisplay::RenderFrameWithDRM(int iDrmPrimefd, int Width, int Height)
{
	int ret;
	uint32_t handles[4] = {0};

	// 将新的 dma-buf fd 转换为 handle
	ret = drmPrimeFDToHandle(iDevfd, iDrmPrimefd, &handles[0]);
	if (ret) {
		perror("drmPrimeFDToHandle failed");
		return -1;
	}

	ret = drmPrimeFDToHandle(iDevfd, iDrmPrimefd, &handles[1]);
	if (ret) {
		perror("drmPrimeFDToHandle failed");
		return -1;
	}
	uint32_t iFramebufferId;
	for (DRMFramebuffer element : vtDRMFramebuffers) {
        if(element.DrmPrimefd == iDrmPrimefd){
			iFramebufferId = element.FramebufferId;
		}
    }

	// 构造原子请求
	/* atomic plane update */
	// req = drmModeAtomicAlloc();
	drmModeAtomicAddProperty(pAtomicReq, iPlaneId, iPropertyCrtcId, iCrtcId);
	drmModeAtomicAddProperty(pAtomicReq, iPlaneId, iPropertyfbId, iFramebufferId);
	// 显示屏幕的切割
	drmModeAtomicAddProperty(pAtomicReq, iPlaneId, iPropertyCrtcX, 0);
	drmModeAtomicAddProperty(pAtomicReq, iPlaneId, iPropertyCrtcY, 0);
	drmModeAtomicAddProperty(pAtomicReq, iPlaneId, iPropertyCrtcW, Width);
	drmModeAtomicAddProperty(pAtomicReq, iPlaneId, iPropertyCrtcH, Height);
	// framebuff的切割
	drmModeAtomicAddProperty(pAtomicReq, iPlaneId, iPropertySrcX, 0);
	drmModeAtomicAddProperty(pAtomicReq, iPlaneId, iPropertySrcY, 0);
	drmModeAtomicAddProperty(pAtomicReq, iPlaneId, iPropertySrcW, Width << 16);
	drmModeAtomicAddProperty(pAtomicReq, iPlaneId, iPropertySrcH, Height << 16);
	ret = drmModeAtomicCommit(iDevfd, pAtomicReq, 0, NULL);

	if (ret) {
		perror("drmModeAtomicCommit failed");
		return -1;
	}

	// printf("Atomic frame update committed successfully\n");
	return 0;
}